package org.kth.dks.dks_marshal;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.kth.dks.dks_comm.DKSRef;

public abstract class DKSMessage {

  private static Logger log = Logger.getLogger(DKSMessage.class);
  protected static Map messageMapUnsync = new HashMap(); // maps an XMLTAG to a DKSMessage type
  protected static Map messageMap = Collections.synchronizedMap(messageMapUnsync);
  private static final String BASEPACKAGE = "org.kth.dks.";
  private DKSRef sendRef = null;
  private DKSRef recvRef = null;

  public DKSMessage() {
//    marshaler = new MarshalXML(this);
      marshaler = new MarshalBinary(this);
  }

  public final DKSRef getSendRef() { return sendRef; }
  public final DKSRef getRecvRef() { return recvRef; }
  public final void setSendRef(DKSRef s) { sendRef = s; }
  public final void setRecvRef(DKSRef r) { recvRef = r; }

  public static DKSMessage unmarshal(byte[] raw) {
    return unmarshal((byte) DKSMarshal.TRANSDEFAULT, raw);
  }

  public static DKSMessage unmarshal(byte transType, byte[] raw) {
    switch (transType) {
      case DKSMarshal.TRANSTYPEXML:
        return MarshalXML.unflatten(raw);
      case DKSMarshal.TRANSTYPEBINARY:
        return MarshalBinary.unflatten(raw);
      default:
        log.error( "Could not understand tranport type in incoming message, ignoring.");
        return null;
    }
  }

  /**
   * Adds a TAG string, e.g. "LOOKUPMSG", into a Map which maps it to a DKSMessage (narrowed) class, e.g. "dks_marshal.LookupMsg"
   * Used to initially by the application and DKSNode to install message types and their corresponding class
   * @param msgInternalXMLTAG String Tag describing the message
   * @param nameOfClass String Fully qualified (absolute) name of the class  (example: org.kth.dks.MyClass)
   */
  public static synchronized void addMessageType(String msgInternalXMLTAG, String nameOfClass) {
    String className = nameOfClass;
    try {
      messageMap.put(msgInternalXMLTAG,
                     Class.forName(className));
    } catch (ClassNotFoundException ex) {
      log.error(
                     "Class not found, could not install unmarshaller for message ("+className+")\n");
    }
  }

  /**
   * Adds a TAG string, e.g. "LOOKUPMSG", into a Map which maps it to a DKSMessage (narrowed) class, e.g. "dks_marshal.LookupMsg"
   * Used to initially by the application and DKSNode to install message types and their corresponding class
   * @param msgInternalXMLTAG String Tag describing the message
   * @param nameOfClass String name of the class relative to the package org.kth.dks (this.BASEPACKAGE)
   */
  public static synchronized void addMessageTypePrefixed(String msgInternalXMLTAG, String nameOfClass) {
    String className = BASEPACKAGE + nameOfClass;
    try {
      messageMap.put(msgInternalXMLTAG,
                     Class.forName(className));
    } catch (ClassNotFoundException ex) {
      log.error(
                     "Class not found, could not install unmarshaller for message ("+className+")\n");
    }
  }

  public abstract String getName();

  public abstract void marshal() throws IOException;

  public abstract void unmarshal() throws IOException;

  protected MarshalInterface marshaler;

  protected int pCount = 0;
  protected XMLMessage xmsg = null;
  protected XMLElement ele;
  protected int eleCnt = 0;

  public final byte[] flatten() {
    switch (DKSMarshal.TRANSDEFAULT) {
      case DKSMarshal.TRANSTYPEXML:
        return marshaler.flatten();
      case DKSMarshal.TRANSTYPEBINARY:
        return marshaler.flatten();
      default:
        log.error( "Could not understand tranport type in incoming message, ignoring. (flatten)");
        return null;
    }
  }

  /*
  public final void unflatten(XMLMessage m) {
    marshaler.unflatten(m);
  }
*/
/*
  public synchronized static DKSMessage unflatten(byte []data) {
    return marshaler.unflatten(data);
  }
*/
}
